﻿using CustomCharacter;
using Exiled.API.Enums;
using Exiled.API.Features;
using Exiled.API.Features.Doors;
using Exiled.API.Features.Roles;
using Exiled.Events.EventArgs.Player;
using Exiled.Events.EventArgs.Server;
using MEC;
using PlayerStatsSystem;
using RgCore.Events;
using RgCore.PlayerHud;
using System;
using System.Collections.Generic;
using System.Linq;
using RgCore.CustomSide;
using UnityEngine;
using RgCore.Modules;

namespace ClassDProtector
{
    public class ClassDProtectorPlugin : RgPlugin
    {
        public override string Name => "D级保护插件";

        public override string Id => "classd_protector";
        public static ClassDProtectorPlugin singleton;
        public CoroutineHandle Coroutine;
        public List<Player> Innocents = null;
        public List<Player> Dying = null;

        public override void OnDisabled()
        {
            base.OnDisabled();
            Innocents = null;
            Dying = null;
            Timing.KillCoroutines(Coroutine);
            EventProcessor.OnHurting.Unsubscribe(OnHurting);
            EventProcessor.DamageResulting.Unsubscribe(DamageResulting);
            EventProcessor.OnDying.Unsubscribe(OnDying);
            EventProcessor.ReadyDying.Unsubscribe(ReadyDying);
            Exiled.Events.Handlers.Server.RespawningTeam -= Server_RespawningTeam;
            Exiled.Events.Handlers.Player.Escaping -= Player_Escaping;
            Exiled.Events.Handlers.Server.RoundEnded -= Server_RoundEnded;
            Exiled.Events.Handlers.Player.ChangingRole -= Player_ChangingRole;
        }

        public override void OnEnabled()
        {
            base.OnEnabled();
            singleton = this;
            Innocents = new List<Player>();
            Dying = new List<Player>();
            Coroutine = Timing.RunCoroutine(Update());
            EventProcessor.OnHurting.Subscribe(OnHurting);
            EventProcessor.DamageResulting.Subscribe(DamageResulting);
            EventProcessor.OnDying.Subscribe(OnDying);
            EventProcessor.ReadyDying.Subscribe(ReadyDying);
            Exiled.Events.Handlers.Server.RespawningTeam += Server_RespawningTeam;
            Exiled.Events.Handlers.Player.Escaping += Player_Escaping;
            Exiled.Events.Handlers.Server.RoundEnded += Server_RoundEnded;
            Exiled.Events.Handlers.Player.ChangingRole += Player_ChangingRole;
        }
        private IEnumerator<float> Update()
        {
            while (true)
            {
                try
                {
                    for (int i = 0; i < Dying.Count; i++)
                    {
                        var dying = Dying[i];
                        if (dying.Zone == ZoneType.Surface)
                         dying.ReferenceHub.playerStats.DealDamage(new CustomReasonDamageHandler("[D级保护] 安全区自动捆绑扣血", 0.5f));
                    }
                }
                catch (Exception ex)
                {
                    Log.Error(ex);
                }
                yield return Timing.WaitForSeconds(1.0f);
            }
        }
        private void Server_RespawningTeam(RespawningTeamEventArgs ev)
        {
            if (ev.NextKnownTeam == Respawning.SpawnableTeamType.ChaosInsurgency)
                Innocents.Clear();
        }
        private void Server_RoundEnded(RoundEndedEventArgs ev)
        {
            Innocents.Clear();
            Dying.Clear();
        }
        private bool InSafeZone(Player player)
        {
            float distance = float.MaxValue;
            if (player.Zone == ZoneType.Surface)
                return true;
            foreach (var door in Door.List.Where(x => x.Name == "GATE_A" || x.Name == "GATE_B"))
            {
                distance = Mathf.Min(distance, Vector3.Distance(player.Position, door.Position));
            }
            foreach (var scp in Player.List.Where(x => x.GetSide() == Side.Scp))
            {
                distance = Mathf.Min(distance, Vector3.Distance(player.Position, scp.Position));
            }
            if (distance <= 20f)
                return true;
            return false;
        }
        private void ReadyDying(DamageResultingEventArgs ev) //100%要死了
        {
            if (Round.InProgress)
            {
                if (ev.DamageHandler is AttackerDamageHandler && 
                    ev.Attacker.GetSide() == Side.Mtf && 
                    ev.Attacker.Role.Team != PlayerRoles.Team.Scientists && 
                    Innocents.Contains(ev.Player) && 
                    ev.Player.Role is FpcRole role)
                {
                    if (role.MoveState != PlayerRoles.FirstPersonControl.PlayerMovementState.Sprinting &&
                        !ev.Player.Inventory.UserInventory.Items.Any(x =>
                    x.Value.Category == ItemCategory.Firearm ||
                    x.Value.Category == ItemCategory.MicroHID ||
                    x.Value.Category == ItemCategory.Grenade))
                    {
                        ev.Attacker.Ban(900, "[D级保护] 击杀无辜&未持枪D级后15分钟封禁惩罚");
                        ev.Player.SendFormattedMsg("d_protection", "<color=#EEAD0E>D级保护系统</color>", $"攻击方 <color=yellow>{ev.Attacker.Nickname}</color> 已遭到15分钟封禁。", 5, MsgType.Notification, ScreenLocation.CenterTop, true);
                    }
                }
            }
            Innocents.Remove(ev.Player);
            Dying.Remove(ev.Player);
        }
        private void OnHurting(HurtingEventArgs ev) //被打前
        {
            if (ev.DamageHandler.Base is AttackerDamageHandler && ev.Attacker.GetSide() == Side.Mtf && ev.Player.IsCuffed && ev.Player.Role.Team == PlayerRoles.Team.ClassD && ev.Player.GetSide() == Side.ChaosInsurgency && CustomCharacterCheck(ev.Player))
            {
                ev.IsAllowed = false;
                ev.Amount = 0f;
            }
        }
        private void OnDying(DyingEventArgs ev) //要死了
        {
            if (ev.DamageHandler.Base is AttackerDamageHandler && Innocents.Contains(ev.Player) && ev.Attacker.GetSide() == Side.Mtf)
            {
                if (InSafeZone(ev.Player))
                {
                    goto FORBID;
                }
                else if (ev.Attacker.Role.Type == PlayerRoles.RoleTypeId.Scientist)
                {
                    float distance = float.MaxValue;
                    foreach (var mtf in Player.List.Where(x => x.GetSide() == Side.Mtf && x.Role.Type != PlayerRoles.RoleTypeId.Scientist))
                    {
                        distance = Mathf.Min(distance, Vector3.Distance(mtf.Position, ev.Player.Position));
                    }
                    if (distance <= 15f)
                    {
                        goto FORBID;
                    }
                }
                return;
            FORBID:
                ev.IsAllowed = false;
                ev.Player.Heal(100f);
                Timing.CallDelayed(0.2f, delegate ()
                {
                    ev.Player.Heal(100f);
                    if (!Dying.Contains(ev.Player))
                    {
                      Dying.Add(ev.Player);
                    }
                });
                ev.Player.Cuffer = ev.Attacker;
                ev.Attacker.SendFormattedMsg("d_protection", "<color=#EEAD0E>D级保护系统</color>", $"玩家 <color=#00FF00>{ev.Player.Nickname}</color> 已被你捆绑", 5, MsgType.Notification, ScreenLocation.CenterTop, true);
                ev.Player.SendFormattedMsg("d_protection", "<color=#EEAD0E>D级保护系统</color>", "你已被捆绑保护，并持续扣血，请尽快撤离。", 5, MsgType.Notification, ScreenLocation.CenterTop, true);
            }
        }
        private void DamageResulting(DamageResultingEventArgs ev) //承伤
        {
            if (ev.DamageHandler is AttackerDamageHandler && Innocents.Contains(ev.Attacker) && ev.Attacker != ev.Player)
            {
                if (ev.Attacker.GetSide() == Side.ChaosInsurgency && ev.Attacker.Role.Team == PlayerRoles.Team.ClassD && ev.Player.Role.Side == Side.Mtf)
                {
                    Innocents.Remove(ev.Attacker);
                }
            }
        }
        private bool CustomCharacterCheck(Player player)
        {
            var cc = player.GetCharacterInstance();
            return cc?.Attribute.FollowRole != false;
        }
        private void Player_ChangingRole(ChangingRoleEventArgs ev)
        {
            Innocents.Remove(ev.Player);
            Dying.Remove(ev.Player);
            if (Round.InProgress)
            {
                Timing.CallDelayed(1.0f, delegate ()
                {
                    if (ev.Player.Role.Team == PlayerRoles.Team.ClassD)
                    {
                        bool flag = !ModuleManager.IsLoaded("CustomCharacter") || CustomCharacterCheck(ev.Player);
                        if (flag)
                            Innocents.Add(ev.Player);
                    }
                });
            }
        }
        private void Player_Escaping(EscapingEventArgs ev)
        {
            Dying.Remove(ev.Player);
        }
    }
}
